﻿#include "soundbank/ModelByteBuffer.h"
#include "lang/Exception.h"
using namespace yzrilyzr_util;
using namespace yzrilyzr_io;
using namespace yzrilyzr_collection;
using namespace yzrilyzr_array;
using namespace yzrilyzr_lang;
namespace yzrilyzr_soundbank{
	/*RandomFileInputStream::RandomFileInputStream(){
		raf=std::make_shared<RandomAccessFile>(root.file, "r");
		raf.seek(root.fileoffset + arrayOffset());
		left=parent->capacity();
	}
	int32_t RandomFileInputStream::read(){
		if(left == 0)
			return -1;
		int b=raf.read();
		if(b == -1)
			return -1;
		left--;
		return b;
	}
	int64_t RandomFileInputStream::read(ByteArray & b){
		int len=b.length;
		if(len > left)
			len=(int)left;
		if(left == 0)
			return -1;
		len=raf.read(b, 0, len);
		if(len == -1)
			return -1;
		left-=len;
		return len;
	}
	int64_t RandomFileInputStream::read(ByteArray & b, u_index off, u_index len){
		if(len > left)
			len=(int)left;
		if(left == 0)
			return -1;
		len=raf.read(b, off, len);
		if(len == -1)
			return -1;
		left-=len;
		return len;
	}
	u_index RandomFileInputStream::skip(u_index n){
		if(n < 0)
			return 0;
		if(n > left)
			n=left;
		int64_t p=raf.getFilePointer();
		raf.seek(p + n);
		left-=n;
		return n;
	}
	u_index RandomFileInputStream::available(){
		if(left > 0x7fffffff)
			return 0x7fffffff;
		return (u_index)left;
	}
	void RandomFileInputStream::close(){
		raf.close();
	}
	void RandomFileInputStream::mark(int32_t readlimit){
		try{
			_mark=raf.getFilePointer();
			markleft=left;
		} catch(IOException e){
			e.printStackTrace();
		}
	}
	void RandomFileInputStream::reset(){
		raf.seek(mark);
		left=markleft;
	}
	bool RandomFileInputStream::markSupported(){
		return true;
	}*/
	//############################
	ModelByteBuffer::ModelByteBuffer(ModelByteBuffer * parent, int64_t beginIndex, int64_t endIndex, bool independent){
		this->root=parent->root;
		int64_t parent_len=parent->len;
		if(beginIndex < 0)
			beginIndex=0;
		if(beginIndex > parent_len)
			beginIndex=parent_len;
		if(endIndex < 0)
			endIndex=0;
		if(endIndex > parent_len)
			endIndex=parent_len;
		if(beginIndex > endIndex)
			beginIndex=endIndex;
		offset=beginIndex;
		len=endIndex - beginIndex;
		if(independent){
			buffer=root->buffer;
			if(root->file != nullptr){
				file=root->file;
				fileoffset=root->fileoffset + arrayOffset();
				offset=0;
			} else
				offset=arrayOffset();
			root=this;
		}
	}
	ModelByteBuffer::ModelByteBuffer(std::shared_ptr<ByteArray> buffer){
		this->buffer=buffer;
		this->offset=0;
		this->len=buffer->length;
	}
	ModelByteBuffer::ModelByteBuffer(std::shared_ptr<ByteArray> buffer, u_index offset, u_index len){
		this->buffer=buffer;
		this->offset=offset;
		this->len=len;
	}
	ModelByteBuffer::ModelByteBuffer(File * file){
		this->file=file;
		this->fileoffset=0;
		this->len=file->length();
	}
	ModelByteBuffer::ModelByteBuffer(File * file, u_index offset, u_index len){
		this->file=file;
		this->fileoffset=offset;
		this->len=len;
	}
	void ModelByteBuffer::loadAll(ArrayList<ModelByteBuffer> & col){
		/*File selfile = nullptr;
		RandomAccessFile raf = nullptr;
		try {
			for (ModelByteBuffer* mbuff : col) {
				mbuff = mbuff.root;
				if (mbuff.file == nullptr)
					continue;
				if (mbuff.buffer != nullptr)
					continue;
				if (selfile == nullptr || !selfile.equals(mbuff.file)) {
					if (raf != nullptr) {
						raf.close();
						raf = nullptr;
					}
					selfile = mbuff.file;
					raf = new RandomAccessFile(mbuff.file, "r");
				}
				raf.seek(mbuff.fileoffset);
				byte[] buffer = new byte[(int)mbuff.capacity()];
				int read = 0;
				int avail = buffer.length;
				while (read != avail) {
					if (avail - read > 65536) {
						raf.readFully(buffer, read, 65536);
						read += 65536;
					}
					else {
						raf.readFully(buffer, read, avail - read);
						read = avail;
					}
				}
				mbuff.buffer = buffer;
				mbuff.offset = 0;
			}
		}
		finally {
			if (raf != nullptr)
				raf.close();
		}*/
		throw Exception("Unimplemented");
	}
	int64_t ModelByteBuffer::capacity(){
		return len;
	}
	void ModelByteBuffer::writeTo(OutputStream & out){
		//if (root.file != nullptr && root.buffer == nullptr) {
		//	try(InputStream is = getInputStream()) {
		//		//is.transferTo(out);
		//		throw new IOException("");
		//	}
		//}
		//else
		//	out.write(array(), (int)arrayOffset(), (int)capacity());
		throw Exception("Unimplemented");
	}
	InputStream * ModelByteBuffer::getInputStream(){
		//if (root.file != nullptr && root.buffer == nullptr) {
		//	try {
		//		return new ModelByteBuffer.RandomFileInputStream();
		//	}
		//	catch (IOException e) {
		//		//e.printStackTrace();
		//		return nullptr;
		//	}
		//}
		//return new ByteArrayInputStream(array(),
		//	(int)arrayOffset(), (int)capacity());
		throw Exception("Unimplemented");
	}
	std::shared_ptr<ModelByteBuffer> ModelByteBuffer::subbuffer(int64_t beginIndex){
		return subbuffer(beginIndex, capacity());
	}
	std::shared_ptr<ModelByteBuffer> ModelByteBuffer::subbuffer(int64_t beginIndex, int64_t endIndex){
		return subbuffer(beginIndex, endIndex, false);
	}
	std::shared_ptr<ModelByteBuffer> ModelByteBuffer::subbuffer(int64_t beginIndex, int64_t endIndex, bool independent){
		std::shared_ptr<ModelByteBuffer> paramRegPtr(new ModelByteBuffer(this, beginIndex, endIndex, independent));
		return paramRegPtr;
	}
	ByteArray * ModelByteBuffer::array(){
		return root->buffer.get();
	}
	int64_t ModelByteBuffer::arrayOffset(){
		if(root != this)
			return root->arrayOffset() + offset;
		return offset;
	}
	ModelByteBuffer * ModelByteBuffer::getRoot(){
		return root;
	}
	File * ModelByteBuffer::getFile(){
		return file;
	}
	int64_t ModelByteBuffer::getFilePointer(){
		return fileoffset;
	}
	void ModelByteBuffer::load(){
		if(root != this){
			root->load();
			return;
		}
		if(buffer != nullptr)
			return;
		if(file == nullptr){
			throw Exception("No file associated with this ByteBuffer!");
		}
		/*try(InputStream is = getInputStream();
		DataInputStream dis = new DataInputStream(is)) {
			buffer = new byte[(int)capacity()];
			offset = 0;
			dis.readFully(buffer);
		}*/
		throw Exception("Unimplemented");
	}
	void ModelByteBuffer::unload(){
		if(root != this){
			root->unload();
			return;
		}
		if(file == nullptr){
			throw Exception("No file associated with this ByteBuffer!");
		}
		root->buffer=nullptr;
	}
}